/*********************************************************************\
* Dateiname: MTKAPxx.C
* Autor    : Dr. Lurz/Dr. Bathelt
* Projekt  : Multitasking
*
* Copyright (C) Dr. Lurz/Dr. Bathelt
*
* Kurzbeschreibung: Enthaelt Tasks zum Test des Multitaskings.
*
* Datum:     Autor:       Grund der Aenderung:
* 30.09.98   Dr. Lurz     Neuerstellung
* 28.03.99   Dr. Bathelt  Anpassung an C-Richtlinie
* 12.05.99   Dr. Bathelt  Ueberarbeitung und Test
* 01.10.99   Dr. Lurz     Anpassung an RS-Monitor
* 01.09.05   Dr. Lurz     Zeitscheiben (TS) / RR - Scheduling
*
\*********************************************************************/

//#define RS232 ** RS232 Output ! */

/*--- #includes der Form <...> --------------------------------------*/
//#include <conio.h>
#include <stdio.h>
#include <stdlib.h>

/*--- #includes der Form "..." --------------------------------------*/
#include "kernel/mtkkapi.h"
#include "mtkappl.h"

/*--- #define-Konstanten und Makros ---------------------------------*/

#define RES 0   /* RES = 0: Use Semaphore; RES = 1: Use Ressource    */

/*- Symbols / Numbers for Events, Semaphores -*/
#define EVT_A   0x01
#define EVT_B   0x02
#define EVT_C   0x04
#define EVT_D   0x08

#define SID_A   0
#define SID_B   1

#define RID_A   0
#define R_A_PRIO 2

#define DATA_1   'k'
#define DATA_2   'K'
#define DATA_0   "kkkk "
#define DATA_MAX 4


/*- Defines "Length of Tasks" -*/
#define LOOP_CNT_0   4
#define LOOP_CNT_1   4
#define LOOP_CNT_2   4

#ifdef atmega16
#define WORK_CNT   500
#define DO_WORK(n) \
        {\
           volatile unsigned int i;\
           for ( i=0; i < n; i++ );\
        }
#else
#define WORK_CNT   2000000UL
#define DO_WORK(n) \
        {\
           volatile unsigned long int i;\
           for ( i=0; i < n; i++ );\
        }
#endif /* atmega16 */


/*--- Datentypen (typedef) ------------------------------------------*/

/*--- Globale Konstanten --------------------------------------------*/

/*--- Globale Variablen ---------------------------------------------*/

/*--- Modullokale Konstanten ----------------------------------------*/

/*--- Modullokale Variablen -----------------------------------------*/
static unsigned int loop = 1, l_cnt[OS_NR_OF_TASKS+1];

static int sD_use = 0; /*0:sharedData-NotUsed; 1:Sync-OFF; 2:Sync-ON;*/

static char sData[] = DATA_0;

/*--- Prototypen modullokaler Funktionen ----------------------------*/

/*--- Funktionsdefinitionen -----------------------------------------*/

/*********************************************************************\
* Funktionsname: app_init
* Kurzbeschreibung: Initialisiert (static) Variablen der Application
\*********************************************************************/
void app_init( void )
{
   for ( loop = 0; loop <= OS_NR_OF_TASKS; loop++ )
   {
      l_cnt[loop] = 0;
   }
   loop   = 1;
   sD_use = 0;
   
#  ifdef SV_SEM
   if ( sem_init( SID_A, SM_FREE ) != OS_OK )
      io_puts( "Error SEM Init" );
#  endif /* SV_SEM */
#  ifdef SV_RES
   if ( res_init( RID_A, R_A_PRIO ) != OS_OK )
      io_puts( "Error RES Init" );
#  endif /* SV_RES */

#  if (SCHED_RR)
   io_puts( "MTK Start! RR-Sched" );
#  else
   io_puts( "MTK Start! PR-Sched ... " );
#  endif
   
   stk_testa();
   trc_test();
   
   io_puts("#>");
}

/*********************************************************************\
* Funktionsname: ui_stop
* Kurzbeschreibung: Gibt bei Stop System-Statistik aus
*
\*********************************************************************/
static void ui_stop( void )
{
   char buff[20];

   os_disable_int();
   loop = 0;
   
   //trc_outp();
   os_stop();
   
   io_puts("<#");
   
   stk_testa();
   trc_test();
   el_outp();

   io_puts( "T-Loops, " );
   sprintf( buff, "T0: %u ", l_cnt[0] );
   io_puts( buff );
   sprintf( buff, "T1: %u ", l_cnt[1] );
   io_puts( buff );
   sprintf( buff, "T2: %u ", l_cnt[2] );
   io_puts( buff );
   sprintf( buff, "  I: %u",  l_cnt[3] );
   io_puts( buff );
   /*
   l_cnt[3] = l_cnt[0] + l_cnt[1] + l_cnt[2];
   io_puts( "    Rel, " );
   sprintf( buff, "T0: %u T1: %u T2: %u",
             l_cnt[0]*100/l_cnt[3], l_cnt[1]*100/l_cnt[3], l_cnt[2]*100/l_cnt[3] );
   io_puts( buff );
   */
   io_puts("\n");

   //io_puts( "MTK beendet! " );

#  ifndef atmega16
   os_end();
#  endif /* atmega16 */

   //getchar();
   exit(0);
}

/*********************************************************************\
* Funktionsname: ui_run
* Kurzbeschreibung: Bedient die Eingabeschnittstelle (User-Interface)
*
\*********************************************************************/
static int ui_run( void )
{
   int cr;
   //char buffer[100];

      if ( ( cr = io_getc()) == 0 )
      {
         switch ( l_cnt[0] )   //Reaktion nach l_cnt[0]
         {
           case 20000:   //100:
             cr = 'X';
           break;
           default:
           break;
        }
      }

      if ( cr != '\0' )
      {
         //cr = cr | 0x20;
         //cr = cr & 0xDF;
         switch (cr)
         {
            case 's': case 'S':                  //Ausgabe anhalten (kurzzeitig)
              io_puts("<#");
              trc_stop( 1 );
            break;
            case 'q': case 'Q':                  //Ausgabe fortfuehren
              io_puts("#>");
              trc_stop( 0 );
            break;
            case 'e': case 'E':                  //Sync(Sems/Res): ON
              sD_use = 2;
              #if (!RES)
              //io_puts("\nSON ");
              trc_log('S'|('O'<<8), 'N'|0x80);
              #else
              //io_puts("\nR_ON ");
              trc_log('R'|('O'<<8), 'N'|0x80);
              #endif
            break;
            case 'a': case 'A':                  //Sync(Sems/Res): OFF
              sD_use = 1;
              #if (!RES)
              //io_puts("\nSOF ");
              trc_log('S'|('O'<<8), 'F'|0x80);
              #else
              //io_puts("\nR_OFF ");
              trc_log('R'|('O'<<8), 'F'|0x80);
              #endif
            break;
            case '#':                            //Begin / End Trace
              io_puts("<#>");
              break;
            default:
              /*if ( cr == ('#' & 0xDF))
              {
                io_puts("<#>");
                break;
              } */                                  //STOP
              os_disable_int();
              trc_outp();
              ui_stop();

#             ifndef atmega16
              os_end();
#             endif /* atmega16 */

              //getchar();
              exit(0);
              //return 0;
           //break;
         }
         return 1;
      }
      else
         return 1; //0;
}

/*********************************************************************\
* Funktionsname: task_0
*
* Kurzbeschreibung: task_0 gibt, falls ihr die CPU zugeteilt ist,
* die Zeichenkette "Aaaaaab" immer wieder aus.
* Durch Druecken einer beliebigen Taste kann das Multitasking
* ueber task_0 beendet werden.
*
* Parameter: keine
*
* Rueckgabewert: keiner
*
\*********************************************************************/
//void task_0( void )
TASK( task_0 )
{
   //Status  status;
   UValue  cnt;   //= 0;

   while( 1 )
   {
      l_cnt[0]++;
      trc_log( (UValue)T_BGNT0, TID_0 );
      
      ///trc_outp();                                 //Trace-Ausgabe
      if ( !ui_run() ) exit(0); // return;       //User-Interface
      
      
      
      for (cnt = 0; cnt < LOOP_CNT_0; cnt++)
      {
         trc_outp();                                 //Trace-Ausgabe
         
         DO_WORK( WORK_CNT );
         
         
         trc_log( (UValue)T_RUNT0, TID_0 );
         
      }
      
      
      
      trc_log( (UValue)T_ENDT0, TID_0 );
      
   } /* end */ // Idle-Task/Root, No Termination !

}

/*********************************************************************\
* Funktionsname: task_1
*
* Kurzbeschreibung: task_1 gibt, falls ihr die CPU zugeteilt ist,
* die Zeichenkette "Ccccccd" immer wieder aus.
*
* Parameter: keine
*
* Rueckgabewert: keiner
*
\*********************************************************************/
//void task_1( void )
TASK( task_1 )
{
   //Status  status;
   UValue  cnt;   //= 0;

   while( loop )
   {
      l_cnt[1]++;
      trc_log( (UValue)T_BGNT1, TID_1 );
      
      
      for (cnt = 0; cnt < LOOP_CNT_1; cnt++)
      {
         DO_WORK( WORK_CNT );
         
         
         trc_log( (UValue)T_RUNT1, TID_1 );
         
      }
      
      
      trc_log( (UValue)T_ENDT1, TID_1 );
      
   } /* end */
   
   //tsk_term();                      // Terminate Task
   //tsk_chain( TID_2 );
}

/*********************************************************************\
* Funktionsname: task_2
*
* Kurzbeschreibung: task_2 gibt, falls ihr die CPU zugeteilt ist,
* die Zeichenkette "Eeeeeef" immer wieder aus.
*
* Parameter: keine
*
* Rueckgabewert: keiner
*
\*********************************************************************/
//void task_2( void )
TASK( task_2 )
{
   //Status  status;
   UValue  cnt;   //= 0;
   
   while( loop )
   {
      //trc_outp();                                //Trace-Ausgabe
      l_cnt[2]++;
      trc_log( (UValue)T_BGNT2, TID_2 );
      
      
      for (cnt = 0; cnt < LOOP_CNT_2; cnt++)
      {
         DO_WORK( WORK_CNT );
         
         
         
         trc_log( (UValue)T_RUNT2, TID_2 );
         
      }
      
      
      trc_log( (UValue)T_ENDT2, TID_2 );
      
   } /* end */
   
   //tsk_term();                      // Terminate Task
   //tsk_chain( TID_1 );
}


/*********************************************************************\
* Funktionsname: tm_isr
*
* Description: Interrupt Service Routine; Called by Timer Interrupt
* Parameters : none
* Returns    : none
* Attention  : No local Stack-Data in ISR by call int_return() !!!
\*********************************************************************/
//void tm_isr( void )
IntSR( tm_isr )
{
  l_cnt[3]++;

# ifdef atmega16
  if ( l_cnt[3] % 2 == 0 )
# endif /* atmega16 */
  {
    int_enter();                   // Begin Interrupt Routine !
    trc_log( (UValue)T_INTTM, IID_TM );

    tm_tick( 1U );                   // Call Timer-Service !



    tsk_schedule();                //Scheduling in Timer-Int; (Zeitscheiben)

    int_return();                  // End Interrupt Routine !
  }
}


/*********************************************************************\
* Funktionsname: sem_op
* Kurzbeschreibung: Set/Reset Variable f. sharedData-Verwendung in Appl.
\*********************************************************************/
void sem_op( int val )
{
   sD_use = val;
}
